﻿//*** Guidance generated code ***//
using System;
using System.Collections.Generic;

using System.IO;
using System.Linq;
using System.Web;

using ProjectBase.Core;
using ProjectBase.Data;

using $prjsn$.Common;
using $prjsn$.Common.Data.Services;
using $prjsn$.Entity.Services;

namespace $safeprojectname$.Services
{
    public class AttachmentDao : IAttachmentDao
    {
        #region IAttachmentDao Get
        /// <summary>
        ///     Returns all files nested in the article folder
        /// </summary>
        /// <param name = "article"></param>
        /// <returns></returns>
        public virtual IEnumerable<Attachment> GetByArticle(Article article)
        {
            var list = new List<Attachment>();

            var directoryPath = GetDirecotry(article);
            if (directoryPath.IsEmpty())
            {
                return list;
            }
            var di = new DirectoryInfo(directoryPath);
            if (!di.Exists)
            {
                return list;
            }

            var files = di.GetFiles();
            foreach (var file in files)
            {
                var entity = new Attachment
                {
                    Name = file.Name,
                    FullName = file.FullName,
                    Suffix = file.Extension,
                    RelativePath = GetFileRealtivePath(file.Name, article),
                    Article = article,
                };
                list.Add(entity);
            }
            return list;
        }

        /// <summary>
        ///     Returns the file nested in the article folder with matching fileName
        /// </summary>
        /// <param name = "fileName"></param>
        /// <param name = "article"></param>
        /// <returns></returns>
        public virtual Attachment GetByName(string fileName, Article article)
        {
            return GetByArticle(article).Where(e => e.ID.IsEqual(fileName)).FirstOrDefault();
        }
        #endregion IAttachmentDao Get

        #region IAttachmentDao Set
        public virtual Attachment AddOrUpdate(Attachment entity)
        {
            try
            {
                var di = new DirectoryInfo(GetDirecotry(entity.Article));
                if (!di.Exists)
                {
                    di.Create();
                    di.Refresh();
                }

                entity.FullName = GetFullFileName(entity.Name, entity.Article);

                using (var fs = new FileStream(entity.FullName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None)
                    )
                {
                    const int length = 256;
                    var buffer = new Byte[length];
                    var bytesRead = entity.InputStream.Read(buffer, 0, length);

                    while (bytesRead > 0)
                    {
                        fs.Write(buffer, 0, bytesRead);
                        bytesRead = entity.InputStream.Read(buffer, 0, length);
                    }
                }
            }
            catch (Exception ex)
            {
                this.PublishFatal("Cannot save file", ex);
            }
            finally
            {
                entity.InputStream.Close();
            }

            entity.RelativePath = GetFileRealtivePath(entity.Name, entity.Article);

            return entity;
        }

        public virtual void Delete(Attachment entity)
        {
            var fileInfo = new FileInfo(GetFullFileName(entity.Name, entity.Article));
            if (fileInfo.Exists)
            {
                fileInfo.Delete();
            }
        }

        public virtual void ClearAttachments(Article article)
        {
            var directory = GetDirecotry(article);
            var di = new DirectoryInfo(directory);
            if (di.Exists)
            {
                di.Delete(true);
            }
        }
        #endregion IAttachmentDao Set

        #region protected File
        /// <summary>
        ///     Returns the absolute path to the folder based on:
        ///     1) Article.Code = the final folder (e.g. '/Basics'
        ///     2) Project.Settings.ArticleFilesCommonPath parent subfolder (default value "/files/")
        ///     3) absolute path based on run-time
        /// </summary>
        /// <param name = "article"></param>
        /// <returns></returns>
        protected virtual string GetDirecotry(Article article)
        {
            try
            {
                var relative = GetDirectoryRelativePath(article);
                return Global.CreateAbsolutePath(relative);
            }
            catch (Exception ex)
            {
                this.PublishFatal(ex);
            }
            return null;
        }

        protected virtual string GetDirectoryRelativePath(Article article)
        {
            try
            {
                return Path.Combine(Project.Settings.ArticleFilesCommonPath, article.Code);
            }
            catch (Exception ex)
            {
                this.PublishFatal(ex);
            }
            return null;
        }

        protected virtual string GetFileRealtivePath(string fileName, Article article)
        {
            var directory = GetDirectoryRelativePath(article);
            return directory + "/" + HttpUtility.UrlEncode(fileName);
        }

        protected virtual string GetFullFileName(string fileName, Article article)
        {
            var relative = GetDirectoryRelativePath(article);
            relative = Path.Combine(relative, fileName);
            return Global.CreateAbsolutePath(relative);
        }
        #endregion protected File
    }
}